﻿using System;

/*
 * 创建人：
 * 
 * 时间：
 * 
 * 说明：
 * 
 * 
 * 修改说明：
 * 
 * 
 */


namespace ConsoleTest.ChapterSeven
{

    public class DynamicAssembly
    {
        /*创建动态程序集的理由：
         * 
         * 1、Web浏览器中的脚本动态构造一个程序集并以持久化的方式保存到客户端
         * 2、Asp.net页面执行脚本动态创建程序集，并保存到服务器
         * 3、在执行期间编译一个正则表达式。
         */

        

        /*System.Reflection.Emit下常用的类的参考
         * Namespace.Class
 System.Reflection.Emit.AssemblyBuilder
 
主要用途
 定义动态的.NET程序集:一种自我描述的 .NET内建块.动态程序集是通过反射发出特意产生的. 该类继承于System.Reflection.Assembly.
 
范例
 Dim ab As AssemblyBuilder
Dim ad As AppDomainad = Thread.GetDomain()
ab = ad.DefineDynamicAssembly(name,AssemblyBuilderAccess.Run)
 
Namespace.Class
System.Reflection.Emit.ConstructorBuilder
 
主要用途
 用于创建和声明一个动态类的构造器.它囊括了有关构造器的所有信息，包括：名称，方法签名和主体代码.仅仅在你需要创建一个带参数的构造器或者需要覆盖父类构造器的默认行为的时候.
 
范例
 Dim ourClass As TypeBuilder = [module].DefineType("ourClass", _TypeAttributes.Public)
Dim ctorArgs As Type() = {GetType(String)}
Dim ctor As ConstructorBuilder = _ourClass.DefineConstructor(MethodAttributes.Public, _CallingConventions.Standard, constructorArgs)
 
Namespace.Class
 System.Reflection.Emit.CustomAttributeBuilder
 
主要用途
 用于创建动态类的自定义特性.
 
Namespace.Class
 System.Reflection.Emit.EnumBuilder
 
主要用途
 定义和声明枚举.
 
Namespace.Class
 System.Reflection.Emit.EventBuilder
 
主要用途
 为动态类创建事件.
 
Namespace.Class
 System.Reflection.Emit.FieldBuilder
 
主要用途
 为动态类创建字段.
 
Namespace.Class
 System.Reflection.Emit.ILGenerator
 
主要用途
 用于产生MSIL代码.
 
范例
 Dim gen As ILGenerator = someMethod.GetILGenerator()gen.Emit(OpCodes.Ldarg_0)gen.Emit(OpCodes.Ret)
 
Namespace.Class
 System.Reflection.Emit.LocalBuilder
 
主要用途
 创建方法或构造器的局部变量.
 
Namespace.Class
 System.Reflection.Emit.MethodBuilder
 
主要用途
 用于创建和声明动态类的方法.
 
Namespace.Class
 System.Reflection.Emit.MethodRental
 
主要用途
 一个很实用的类，用于从别的类中交换一个方法到动态创建的类中。当你需要快速重建一个已经在其它地方存在的方法时，就显得非常有用。
 
Namespace.Class
 System.Reflection.Emit.ParameterBuilder
 
主要用途
 为方法的签名创建参数.
 
Namespace.Class
 System.Reflection.Emit.PropertyBuilder
 
主要用途
 为动态的类型创建属性.
 

         */


        //说明：一下三个方法皆以 p(x)=66x^3+83x^2-13735x+30139
        //多项式计算为目标
        //多项式计算方式：p(x=30139+x(-13735+x(83+66x))

        /// <summary>
        /// 多项式计算通用方法
        /// </summary>
        private static int CommonEval(int x,int[] Coefs)
        {
            int tmp = 0;
            int degree = Coefs.GetLength(0);
            for (int i = degree - 1; i >= 0; i--)
            {
                //从后向前x的幂以此降低
                tmp = Coefs[i] + x * tmp;

            }
            return tmp;
        }

        /// <summary>
        /// 
        /// </summary>
        public static void CallCommon()
        {

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            int[] coefs = { 30139,-13735,83,66};
            sw.Start();
            for (int x = -26; x < 19; x++)
            {
               
                for (int i = 0; i < 10000000; i++)
                {
                    CommonEval(x, coefs);
                }
            }
            //通用方法执行时间大约为 16.98秒
            System.Console.WriteLine("CommonEval Duration:"+sw.Elapsed.TotalMilliseconds.ToString());
        }

        /// <summary>
        /// 特殊化的计算方法
        /// </summary>
        /// <param name="x"></param>
        private static int CustomEval(int x)
        {
            return 30139+x*(-13735+x*(83+66*x));
        }

        /// <summary>
        /// 
        /// </summary>
        public static void CallCustom()
        {

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            for (int x = -26; x < 19; x++)
            {
                
                for (int i = 0; i < 10000000; i++)
                {
                    CustomEval(x);
                }
            }
            //特殊化的方法执行时间大约为3.9秒左右
            System.Console.WriteLine("CustomEval Duration:" + sw.Elapsed.TotalMilliseconds.ToString());
        }

        //通过特殊化方法与通用化方法对比发现特殊化方法执行效率大约为通用化方法执行效率4倍
        //优化方法与通用方法的共同点还在于方法中的系数都是编译时已知的
        //.NET为我们提供了另外一种能够在执行时接受系数的，并且优化的解决方法-----动态构造程序集

        public static void CallDynamic()
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            int[] coefs = { 30139,-13735,83,66};
            Polynome p = new Polynome(coefs);
            sw.Start();
            for (int x = -26; x < 19; x++)
            {
                for (int i = 0; i < 10000000; i++)
                {
                    p.polynome.Eval(x);
                }

            }
            System.Console.WriteLine("CustomEval Duration:" + sw.Elapsed.TotalMilliseconds.ToString());
        }

    }

    public interface IPolynome
    {
        int Eval(int x);
    }
    public class Polynome
    {
        public IPolynome polynome;
        public Polynome(int[] coefs)
        {
            System.Reflection.Assembly asm=buildecodeInternal(coefs);
            polynome=(IPolynome)asm.CreateInstance("PolynomeInternal");
        }

        private System.Reflection .Assembly buildecodeInternal(int[] coefs)
        {

            /* 一般的，使用反射发出（reflection emit）可能会是这样子的步骤： 
            1.         创建一个新的程序集（程序集是动态的存在于内存中或把它们保存到磁盘上）。

            2.         在程序集内部，创建一个模块（module）。

            3.         在模块内部，创建一个类型。

            4.         给类型添加属性和方法。

            5.         产生属性和方法内部的代码

            确切得说，当你使用Reflection.Emit类产生代码时，以上描述的是你实际中要遵循的过程。

            */

            System.Reflection.AssemblyName asmName=new System.Reflection.AssemblyName();
            asmName.Name="EvalPolynome";

        System.Reflection.Emit.AssemblyBuilder asmBuilder=
            System.Threading.Thread.GetDomain().DefineDynamicAssembly(asmName
            ,System.Reflection.Emit.AssemblyBuilderAccess.Run);

            System.Reflection.Emit.ModuleBuilder modBuilder=
                asmBuilder.DefineDynamicModule("MainMod");

            System.Reflection.Emit.TypeBuilder typeBuilder=modBuilder.DefineType(
                "PolynomeInternal",System.Reflection.TypeAttributes.Public);
            typeBuilder.AddInterfaceImplementation(typeof(IPolynome));

            System.Reflection.Emit.MethodBuilder methodBuilder=typeBuilder.DefineMethod(
                "Eval"
                ,System.Reflection.MethodAttributes.Public|System.Reflection.MethodAttributes.Virtual
                ,typeof(int)
                ,new Type[]{typeof(int)});

            System.Reflection.Emit.ILGenerator ilGen=methodBuilder.GetILGenerator();
            int deg=coefs.GetLength(0);
            for(int i=0;i<deg-1;i++)
            {
                ilGen.Emit(System.Reflection.Emit.OpCodes.Ldc_I4,coefs[i]);
                ilGen.Emit(System.Reflection.Emit.OpCodes.Ldarg,1);
            }
            ilGen.Emit(System.Reflection.Emit.OpCodes.Ldc_I4,coefs[deg-1]);
            for(int i=0;i<deg-1;i++)
            {
                ilGen.Emit(System.Reflection.Emit.OpCodes.Mul);
                ilGen.Emit(System.Reflection.Emit.OpCodes.Add);
            }

             ilGen.Emit(System.Reflection.Emit.OpCodes.Ret);

             System.Reflection.MethodInfo methodInfo = typeof(IPolynome).GetMethod("Eval");
             typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
             typeBuilder.CreateType();
             return asmBuilder;

    }

    }
}